package com.czq.springioc.ioc;

import com.czq.springioc.stereotype.Autowired;
import com.czq.springioc.stereotype.Component;

import java.io.File;
import java.io.FileNotFoundException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;

/**
 * @author 程子强
 * @Description
 * @date 2024/7/9 9:47
 */
public class SpringIOC {
    private List<String> beanNames;
    private List<String> filePaths;
    private String basePath;
    private String basePackage;
    private Map<String, Object> beans =new HashMap<>();
    //扫描所有文件信息，存放到 filePaths中
    private void scan() throws FileNotFoundException {
        File file = new File(basePath);
        filePaths = new ArrayList<>();
        //文件是否存在
        if (file.exists()) {
            //使用队列采取，广度优先遍历的方法
            Queue<File> queue = new LinkedList<>();
            queue.add(file);
            while (!queue.isEmpty()) {
                File poll = queue.poll();
                if (poll == null) {
                    continue;
                }
                if (poll.isDirectory()) {
                    File[] files = poll.listFiles();
                    for (File f : files) {
                        queue.add(f);
                    }
                } else {
                    //将路径存入
                    filePaths.add(poll.getPath());
                }
            }
        } else {
            throw new FileNotFoundException(basePath + " not found");
        }
    }
    /**
     * 讲所有的.java结尾的 全限定名放到 beanNames
     */
    public void  initBeanNames(){
        for (String s : filePaths) {
            String replace = s.replace(basePath, "");
            if(replace.endsWith(".java")) {
                replace = replace.substring(0, replace.length()-5);
            }

            char[] chars = replace.toCharArray();
            for (int i = 0; i < chars.length; i++) {
                if(chars[i]=='\\'){
                    chars[i] = '.';
                }
            }
            beanNames.add(basePackage+"."+new String(chars));
        }
    }
    public void initBeans(){
        //扫描注解中所有还有Component注解的，并放入beans中
        for (String beanName : beanNames) {
            try {
                Class<?> aClass = Class.forName(beanName);
                Annotation[] declaredAnnotations = aClass.getDeclaredAnnotations();
                for (Annotation declaredAnnotation : declaredAnnotations) {
                    if(declaredAnnotation instanceof Component){
                        Object o = aClass.newInstance();
                        beans.put(aClass.getName(),o);
                    }
                }
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        for (Map.Entry<String, Object> entry : beans.entrySet()) {
            //通过反射获取到beans所有的类中的每一个属性
            Field[] declaredFields = entry.getValue().getClass().getDeclaredFields();
            for (Field field : declaredFields) {
                //获取到该参数的所有注解，并判断是否含有Autowired
                Annotation[] declaredAnnotations = field.getDeclaredAnnotations();
                for (Annotation annotation : declaredAnnotations) {
                    if (annotation instanceof Autowired) {
                        //因为Autowired注解，需要给该对象生成实例，所有我们为这个参数赋值
                        //field.getType().getName(); 获取的是字段的类型名称。
                        //field.getName(); 获取的是字段本身的名称。
                        String name = field.getType().getName();
                        //根据类型从beans中获取对应的对象
                        Object o = beans.get(name);
                        field.setAccessible(true);
                        try {
                            field.set(entry.getValue(), o);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
 //从beans中获取该对象
    public Object getInstance(String beanName) {
        return beans.get(beanName);
    }

    private void initPath(){
        basePath = "E:\\邢台大三青城博雅\\最后的暑假实训\\java基础\\代码\\ioc\\src\\main\\java\\com\\czq\\springioc\\";
        basePackage = "com.czq.springioc";
    }
    public SpringIOC() {
        initPath();
        try {
            scan();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        beanNames= new ArrayList<>();
        initBeanNames();
    }
}
